/*按键驱动——输入子系统*/

/*
//add pwr			
pwr_button {			
	compatible = "rk3399,power-button";		
	gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;		
	interrupt-parent = <&gpio0>;//对应的上级中断控制器是 gpio0		
	interrupts = <5 IRQ_TYPE_EDGE_BOTH>; //中断号 触发方式 GPIO0 A5		
};			
*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <dt-bindings/gpio/gpio.h>
#include <linux/input.h>


/*定义结构体类型*/
struct rk3399_button
{
	unsigned int major;
	struct class* pcls;
	struct device* pdev;
	unsigned int gpio;//引脚号
	int irq;//中断号
	int value;//按键引脚当前电平状态
	int validvalue;//按键引脚有效电平
};

/*全局变量*/
static struct rk3399_button* pbutton;
static struct input_dev* pbutton_inputdev;

//定义id_table表
static const struct platform_device_id button_id_table[] = 
{
	{ .name = "rk3399_button", .driver_data = 0x1 }, 
	{ .name = "rk3288_button", .driver_data = 0x2 }, 
	{ .name = "rk3568_button", .driver_data = 0x3 },
};

//定义compatible匹配表
static const struct of_device_id button_match[] = 
{
	{ .compatible = "rk3399,power-button", },
};


/*中断处理函数*/
static irqreturn_t button_handler(int irq, void *dev_id)
{
	int value;
	printk("<kernel>call function:%s\n",__FUNCTION__);

	/*读取GPIO口电平状态*/
	value = gpio_get_value(pbutton->gpio);
	if(pbutton->validvalue)//如果有效电平为高电平
	{
		input_report_key(pbutton_inputdev, KEY_A, value); //上报事件对象
		input_sync(pbutton_inputdev); //上报完毕
	}
	else
	{
		input_report_key(pbutton_inputdev, KEY_A, !value); //上报事件对象
		input_sync(pbutton_inputdev); //上报完毕
	}		
	
	return IRQ_HANDLED;
}


/*定义probe、remove函数*/
static int button_probe(struct platform_device *pdev)
{
	int ret;
	enum of_gpio_flags flags;
	struct device_node* pbutton_node = NULL;
	printk("<kernel>call function:%s\n",__FUNCTION__);

	/*获取平台数据*/
	pbutton_node = pdev->dev.of_node;

	/*申请分配结构体空间*/
	pbutton = kmalloc(sizeof(struct rk3399_button), GFP_KERNEL);
	if(pbutton == NULL)
	{
		printk("kmalloc fail.\n");
		return -ENOMEM;
	}

	pbutton_inputdev = input_allocate_device();
	if(pbutton_inputdev == NULL)
	{
		printk("input_allocate_device fail.\n");
		ret = -ENOMEM;
		goto err_input_allocate_device;
	}

	/*初始化输入设备*/
	set_bit(EV_KEY, pbutton_inputdev->evbit); //为输入设备对象设置事件类型 EV_KEY 按键事件
	set_bit(KEY_A, pbutton_inputdev->keybit); //为输入设备对象设置键码 KEY_A
	pbutton_inputdev->name = "xyd power key button";
	pbutton_inputdev->phys = "rk3399 power key";
	pbutton_inputdev->id.vendor = 0x11;
	pbutton_inputdev->id.product = 0x22;
	pbutton_inputdev->id.version = 0x30;

	/*注册输入设备*/
	ret = input_register_device(pbutton_inputdev);
	if (ret) 
	{
	   printk("input_register_device fail.\n");
		 ret = -EFAULT;
	   goto err_input_register_device;
	}	

	/*初始化硬件*/
	pbutton->gpio = of_get_named_gpio_flags(pbutton_node, "gpios", 0, &flags);
	if (gpio_is_valid(pbutton->gpio)) //如果获取到的引脚号是有效的
	{
		printk("<kernel>Get gpio of button success!\n");
		printk("<kernel>gpio_button = %d\n", pbutton->gpio);
		if(flags == GPIO_ACTIVE_LOW)
		{
			printk("<kernel>Low is valid.\n");
			pbutton->validvalue = 0;
		}
		else
		{
			printk("<kernel>High is valid.\n");
			pbutton->validvalue = 1;
		}
	} 
	else 
	{
		printk("<kernel>of_get_named_gpio_flags fail.\n");
		return -EFAULT;
	}	
	
	gpio_request(pbutton->gpio, pbutton_node->name);
	gpio_direction_input(pbutton->gpio);//将按键IO口设置为输入方向
	gpio_free(pbutton->gpio);

	/*获取中断号*/
	pbutton->irq = gpio_to_irq(pbutton->gpio);
	printk("<kernel>irq = %d\n",pbutton->irq);

	/*申请中断*/
	ret = request_irq(pbutton->irq, button_handler, IRQ_TYPE_EDGE_BOTH, "pwr_int", NULL);
	if (ret < 0) 
	{
		printk("request_irq fail.\n");
		ret = -EINVAL;
		goto err_request_irq;
	} 

	return 0;

	/*集中容错处理*/
err_request_irq:
	input_unregister_device(pbutton_inputdev);
err_input_register_device:
	input_free_device(pbutton_inputdev);
err_input_allocate_device:
	kfree(pbutton); 	

	return ret;
}

static int button_remove(struct platform_device *pdev)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);

	/*释放中断*/
	free_irq(pbutton->irq, NULL);

	/*注销输入设备*/
	input_unregister_device(pbutton_inputdev);

	/*释放输入设备*/
	input_free_device(pbutton_inputdev);

	/*释放堆区空间*/
	kfree(pbutton);

	return 0;
}


/*定义平台驱动对象*/	
static struct platform_driver button_driver = 
{
	.probe		= button_probe,
	.remove		= button_remove,
	.driver		= {.name	= "rk_button", .of_match_table = button_match,},
	.id_table	= button_id_table,
};


/*入口函数——insmod调用*/
static int __init driver_mod_init(void)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);
	return platform_driver_register(&button_driver);
}

/*出口函数——rmmod调用*/
static void __exit driver_mod_exit(void)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);
	platform_driver_unregister(&button_driver);
}


module_init(driver_mod_init); //告诉内核本模块程序的入口函数名
module_exit(driver_mod_exit);//告诉内核本模块程序的出口函数名
MODULE_LICENSE("GPL"); //遵守开源许可协议



